﻿
Option Explicit On
'*******************************************************************
' Program: pkgVisio
' Author: Albert E Edlund
' Date:
'
' Purpose:
' Working with office object XML
'
'*******************************************************************


#Region " imports "

Imports System
Imports System.Object
Imports System.IO
Imports System.IO.TextReader
' need to reference windowsbase in .net
Imports System.IO.Packaging

' need for dbconnectionstringbuilder used in clsConnections
Imports System.Data.Common

Imports System.Windows
Imports System.Windows.Forms
Imports System.Text.StringBuilder

Imports Microsoft.VisualBasic

Imports System.Text
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel

Imports System.Xml
Imports System.Linq
Imports System.Linq.Enumerable
Imports System.Windows.Input

Imports System.Xml.Serialization
Imports System.Xml.Linq
Imports System.Xml.XPath

Imports ADODB
Imports System.Data
Imports System.Data.OleDb
Imports System.Data.Sql


Imports Microsoft.Practices.EnterpriseLibrary.Common
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging


' visio v15 does not use a xName prefix which may put it into conflict with other open office apps
Imports <xmlns="http://schemas.microsoft.com/office/visio/2012/main">
Imports <xmlns:rs="urn:schemas-microsoft-com:rowset">

' generic namespace for office open xml, used in all of them
Imports <xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

Imports pkgVisio.clsVisPackage
Imports pkgVisio.clsStructures


#End Region


'**********************************************************************************
'
'**********************************************************************************
'
Public Class clsWindows


#Region " Properties and Declarations "

    Public strWinStencil As String = "<Window ID=""1"" " _
        & "WindowType=""Stencil"" WindowState=""67109889"" " _
        & "WindowLeft=""0"" WindowTop=""0"" WindowWidth=""149"" WindowHeight=""654"" " _
        & "Document=""StencilPath"" " _
        & "ParentWindow=""0""> " _
        & "<StencilGroup>10</StencilGroup> " _
        & "<StencilGroupPos>1</StencilGroupPos> " _
        & "</Window>"

    Public Shared strTestStencil As String = "C:\Program Files (x86)\Microsoft Office\Office15\visio content\1033\NETSYM_U.VSSX"
    ' Public Shared strTestStencil As String = "C:\Program Files\Microsoft Office\Office15\visio content\1033\NETSYM_U.VSSX"

    Public Structure itemWindow
        Public WinId As Long
        Public WinType As String
        ' stencils may have a document
        Public WinDocument As String
        Public WinParent As Long
    End Structure

    Private m_colWindows As Collection(Of itemWindow)
    Public Property colWindows As Collection(Of itemWindow)
        Get
            If m_colWindows Is Nothing Then
                m_colWindows = New Collection(Of itemWindow)
            End If
            colWindows = m_colWindows
        End Get
        Set(value As Collection(Of itemWindow))
            m_colWindows = value
        End Set
    End Property


    '
    ' what is the latest document
    '
    Public _xDoc As XDocument
    Public Property xDoc As XDocument
        Get
            Return Me._xDoc
        End Get
        Set(value As XDocument)
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "xDoc is Null.")
            End If
            Me._xDoc = value
        End Set
    End Property

    '
    '
    '
    Public m_visPackage As clsVisPackage
    Public Property visPackage As clsVisPackage
        Get
            visPackage = Me.m_visPackage
        End Get
        Set(value As clsVisPackage)
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "visPackage is Null.")
            End If
            Me.m_visPackage = value
        End Set
    End Property


#End Region


    '
    '
    '
    Public Sub AddStencilWindow(ByRef packageCurrent As Package, ByVal strStencilPath As String)

        Try

            ''
            '' add a stencil window for the fun of it (strNewStencil is a template string defined above)
            ''
            Dim strNewStencil As String = strWinStencil
            Const bufSize As Integer = &H1000
            Dim uniEncoding As New UTF8Encoding
            Dim byteXML As Byte()

            If strStencilPath Is Nothing Then
                strStencilPath = strTestStencil
            End If
            strNewStencil = strNewStencil.Replace("StencilPath", strStencilPath)
            Dim xelemNewWindow As XElement = XElement.Load((XmlReader.Create(New StringReader(strNewStencil))))

            ' go get the windows package part
            Dim pkgpartWindows As PackagePart = Nothing
            If Me._xDoc Is Nothing Then
                Dim colPkgParts As Collection(Of pkgpartInfo) = New Collection(Of pkgpartInfo)
                colPkgParts = Me.visPackage.getPkgPartsByContent(pkgVisio.clsVisPackage.contXmlWindows)
                If colPkgParts.Count = 1 Then
                    Me._xDoc = Nothing
                    If (colPkgParts(0).pkgpartType = pkgpartTypeEnum.Part) And _
                            (colPkgParts(0).pkgpartPath.Contains(".xml")) Then
                        pkgpartWindows = packageCurrent.GetPart(New Uri(colPkgParts(0).pkgpartPath, UriKind.Relative))
                        '  Load the document XML in the part into an XDocument instance.
                        Me.xDoc = XDocument.Load(XmlReader.Create(pkgpartWindows.GetStream()))
                    End If ' test for xml part
                End If ' test for part found
            End If

            ' get the xml from the xDocument as an xElement
            Dim xelemWindow As XElement = xDoc.Elements.FirstOrDefault
            ' add the new window to the existing xElement
            xelemWindow.Add(xelemNewWindow)
            Me._xDoc = Nothing
            Me.xDoc = New XDocument
            ' put the updated xElement into the cleared xDocument
            Me.xDoc.Add(xelemWindow)
            byteXML = uniEncoding.GetBytes(Me.xDoc.ToString)
            ' overwrite the windows package part with the updated data
            Using memStream As New MemoryStream(bufSize)
                memStream.Write(byteXML, 0, byteXML.Length)
                Me.visPackage.CopyStream(memStream, pkgpartWindows.GetStream())
            End Using ' close the memory stream


ExitHandler:
        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try
    End Sub

    '
    ' load a list of Windows names and ids into a list control
    '
    Public Sub loadWindows _
        (ByRef lvControl As ListView)


        Dim lngWinId As Long = -1
        Dim strWinType As String = ""
        Dim strWinDocument As String = ""
        Dim lngWinParent As Long = -1
        Dim tempDoc As XDocument = Nothing


        If m_colWindows Is Nothing Then
            m_colWindows = New Collection(Of itemWindow)
        End If
        m_colWindows.Clear()

        Try

            Dim qryWindow = Me.xDoc...<Window>
            Dim intWindows As Integer = qryWindow.Count
            Dim docWindow As XDocument = Nothing

            If lvControl IsNot Nothing Then
                lvControl.Items.Clear()
                lvControl.Columns.Clear()
                lvControl.View = View.Details
                lvControl.AllowColumnReorder = True
                lvControl.FullRowSelect = True
                lvControl.Columns.Add("Id", 50, HorizontalAlignment.Right)
                lvControl.Columns.Add("WinType", 75, HorizontalAlignment.Left)
                lvControl.Columns.Add("WinDoc", 150, HorizontalAlignment.Left)
                lvControl.Columns.Add("WinPrnt", 50, HorizontalAlignment.Right)
            End If

            ' get the pagesheet information from the pages file
            For Each Window In qryWindow

                Dim lvItem As ListViewItem

                lngWinId = -1
                strWinDocument = "NoDoc"
                strWinType = "Notype"
                lngWinParent = -1


                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In Window.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("{0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "id"
                            lngWinId = CLng(att.Value)
                        Case "document"
                            strWinDocument = CStr(att.Value)
                        Case "parentwindow"
                            lngWinParent = CLng(att.Value)
                        Case "windowtype"
                            strWinType = CStr(att.Value)
                    End Select
                Next att

                ' get the relationship id
                Dim listofElements As IEnumerable(Of XElement) = _
                    From elem In Window.Elements() _
                    Select elem
                For Each elem As XElement In listofElements
                    Select Case LCase(elem.Name.LocalName)
                    End Select
                Next elem


                Dim newWindow As itemWindow = New itemWindow
                newWindow.WinId = lngWinId
                newWindow.WinDocument = strWinDocument
                newWindow.WinParent = lngWinParent
                newWindow.WinType = strWinType
                colWindows.Add(newWindow)

                If lvControl IsNot Nothing Then
                    lvItem = New ListViewItem(lngWinId)
                    lvItem.SubItems.Add(strWinType)
                    lvItem.SubItems.Add(strWinDocument)
                    lvItem.SubItems.Add(lngWinParent)

                    lvControl.Items.Add(lvItem)
                End If ' test for control

            Next Window




        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    '
    '
    Public Sub New(ByVal lclPackage As clsVisPackage)


        Me.m_visPackage = Nothing
        Me.visPackage = New clsVisPackage
        Me.visPackage = lclPackage

    End Sub

End Class
